// 2025/10/11: 首个版本
// 2025/11/20: 优化颜色

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using System.IO;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Layout;
using ASEva;
using ASEva.Utility;
using ASEva.UIAvalonia;
using Avalonia.Media;

namespace CommonSource
{
    partial class SessionGenerationMatrix : DialogPanel
    {
        public SessionGenerationMatrix()
        {
            InitializeComponent();
            SetResizableMode(650, 250, 890, 530);
            language = new LanguageSwitch(Resources, AgencyLocal.GetAppLanguage());
            Title = language["title"];

            if (!AgencyLocal.ClientSide)
            {
                buttonOpenDir.IsVisible = true;
            }

            buttonClear.Click += buttonClear_Click;
            buttonSelectAll.Click += buttonSelectAll_Click;
            buttonSelectNotFinished.Click += buttonSelectNotFinished_Click;
            buttonOpenDir.Click += buttonOpenDir_Click;
            buttonDelete.Click += buttonDelete_Click;

            initializeGrids();
        }

        public String IconResourceName
        {
            set => Icon = ResourceLoader.Load(value)?.ToAvaloniaWindowIcon();
        }

        public override void OnClosing()
        {
            closed = true;
        }

        private void buttonClear_Click(object sender, RoutedEventArgs args)
        {
            foreach (var button in gridButtons)
            {
                if (!button.IsEnabled) continue;
                button.Content = null;
            }
            buttonOpenDir.IsEnabled = buttonDelete.IsEnabled = false;
        }

        private void buttonSelectAll_Click(object sender, RoutedEventArgs args)
        {
            foreach (var button in gridButtons)
            {
                if (!button.IsEnabled) continue;
                button.Content = SelectMark;
            }
            updateButtons();
        }

        private void buttonSelectNotFinished_Click(object sender, RoutedEventArgs args)
        {
            for (int i = 0; i < generations.Length; i++)
            {
                for (int j = 0; j < sessions.Length; j++)
                {
                    var button = gridButtons[i, j];
                    if (!button.IsEnabled) continue;
                    if (gridStatus[i, j] != null && gridStatus[i, j] == GenerationProcessStatus.NotFinished)
                    {
                        if (button.Content as String != SelectMark) button.Content = SelectMark;
                    }
                    else
                    {
                        if (button.Content as String == SelectMark) button.Content = null;
                    }
                }
            }
            updateButtons();
        }

        private async void buttonOpenDir_Click(object sender, RoutedEventArgs args)
        {
            for (int i = 0; i < generations.Length; i++)
            {
                for (int j = 0; j < sessions.Length; j++)
                {
                    var button = gridButtons[i, j];
                    if (button.IsEnabled && button.Content as String == SelectMark)
                    {
                        var genPath = AgencyLocal.GetGenerationPath(sessions[j], generations[i]);
                        if (genPath != null && Directory.Exists(genPath))
                        {
                            if (!AgencyLocal.StartProcess(genPath)) await AgencyLocal.PopupError(language["open-dir-failed"]);
                        }
                        else await AgencyLocal.PopupError(language["path-not-exist"]);
                        return;
                    }
                }
            }
        }

        private async void buttonDelete_Click(object sender, RoutedEventArgs args)
        {
            if (!await AgencyLocal.PopupConfirm(language["confirm-delete"])) return;

            this.IsEnabled = false;

            for (int i = 0; i < generations.Length; i++)
            {
                for (int j = 0; j < sessions.Length; j++)
                {
                    var button = gridButtons[i, j];
                    if (button.IsEnabled && button.Content as String == SelectMark)
                    {
                        await AgencyAsync.RemoveGeneration(sessions[j], generations[i]);
                        if (closed) return;

                        button.Content = null;
                        button.Background = Brushes.Transparent;
                        button.IsEnabled = false;
                        gridStatus[i, j] = null;
                    }
                }
            }

            this.IsEnabled = true;
        }

        private async void initializeGrids()
        {
            sessions = await AgencyAsync.GetSessionList() ?? [];
            generations = await AgencyAsync.GetGenerationList() ?? [];
            gridButtons = new Button[generations.Length, sessions.Length];
            gridStatus = new GenerationProcessStatus?[generations.Length, sessions.Length];

            if (sessions.Length == 0 || generations.Length == 0) return;

            // gridSessionLinks
            var gridSessionLinksDefs = new List<int>();
            for (int i = 0; i < sessions.Length; i++)
            {
                if (i != 0) gridSessionLinksDefs.Add(4);
                gridSessionLinksDefs.Add(24);
            }
            gridSessionLinks.ColumnDefinitions = new ColumnDefinitions(String.Join(',', gridSessionLinksDefs));

            var chinese = AgencyLocal.GetAppLanguage() == Language.Chinese;
            for (int i = 0; i < sessions.Length; i++)
            {
                var sessionIndex = i;

                var button = new Button
                {
                    Content = sessions[i].ToDateTime().ToString(chinese ? "yyyy/MM/dd HH:mm:ss" : "MM/dd/yyyy HH:mm:ss"),
                    FontSize = 12,
                };
                button.Classes.Add("hyperlink");
                button.Click += delegate { selectSession(sessionIndex); };

                var transformControl = new LayoutTransformControl
                {
                    HorizontalAlignment = HorizontalAlignment.Center,
                    VerticalAlignment = VerticalAlignment.Bottom,
                };
                Grid.SetColumn(transformControl, i * 2);
                transformControl.LayoutTransform = new RotateTransform(-90);
                transformControl.Child = button;

                gridSessionLinks.Children.Add(transformControl);
            }

            // gridGenLinks
            var gridGenLinksDefs = new List<int>();
            for (int i = 0; i < generations.Length; i++)
            {
                if (i != 0) gridGenLinksDefs.Add(4);
                gridGenLinksDefs.Add(24);
            }
            gridGenLinks.RowDefinitions = new RowDefinitions(String.Join(',', gridGenLinksDefs));

            for (int i = 0; i < generations.Length; i++)
            {
                var genIndex = i;

                var button = new Button
                {
                    Content = generations[i],
                    FontSize = 12,
                    HorizontalAlignment = HorizontalAlignment.Right,
                };
                button.Classes.Add("hyperlink");
                Grid.SetRow(button, i * 2);
                button.Click += delegate { selectGeneration(genIndex); };

                gridGenLinks.Children.Add(button);
            }

            // grids
            grids.RowDefinitions = new RowDefinitions(String.Join(',', gridGenLinksDefs));

            var tasks = new Task<SessionIdentifier[]>[generations.Length];
            for (int i = 0; i < generations.Length; i++) tasks[i] = AgencyAsync.GetGenerationSessions(generations[i]);
            var generationSessions = await Task.WhenAll(tasks);

            for (int i = 0; i < generations.Length; i++)
            {
                var genIndex = i;
                var targetSessions = (generationSessions[i] ?? []).ToList();

                var gridRow = new Grid { ColumnDefinitions = new ColumnDefinitions(String.Join(',', gridSessionLinksDefs)) };
                Grid.SetRow(gridRow, i * 2);
                grids.Children.Add(gridRow);

                for (int j = 0; j < sessions.Length; j++)
                {
                    var sessionIndex = j;
                    initializeGrid(targetSessions.Contains(sessions[j]), gridRow, genIndex, sessionIndex);
                    if (AgencyLocal.ClientSide) await Task.Delay(4);
                }
            }
        }

        private async void initializeGrid(bool hasGeneration, Grid gridRow, int genIndex, int sessionIndex)
        {
            var button = new Button()
            {
                HorizontalAlignment = HorizontalAlignment.Stretch,
                VerticalAlignment = VerticalAlignment.Stretch,
                HorizontalContentAlignment = HorizontalAlignment.Center,
                VerticalContentAlignment = VerticalAlignment.Center,
                Padding = new Thickness(0),
            };
            Grid.SetColumn(button, sessionIndex * 2);

            if (hasGeneration)
            {
                var status = await AgencyAsync.GetGenerationProcessStatus(sessions[sessionIndex], generations[genIndex]);
                gridStatus[genIndex, sessionIndex] = status;

                if (status == null)
                {
                    button.IsEnabled = false;
                    gridRow.Children.Add(button);
                }
                else
                {
                    switch (status.Value)
                    {
                        case GenerationProcessStatus.Finished:
                            button.Background = Brushes.Green;
                            break;
                        case GenerationProcessStatus.NotFinished:
                            button.Background = Brushes.Red;
                            break;
                        case GenerationProcessStatus.Unknown:
                            button.Background = Brushes.DodgerBlue;
                            break;
                    }
                    button.Click += delegate { selectGrid(genIndex, sessionIndex); };
                    gridRow.Children.Add(button);
                }
            }
            else
            {
                button.IsEnabled = false;
                gridRow.Children.Add(button);
            }

            gridButtons[genIndex, sessionIndex] = button;
        }

        private void selectSession(int sessionIndex)
        {
            bool allSelected = true;
            for (int i = 0; i < generations.Length; i++)
            {
                var button = gridButtons[i, sessionIndex];
                if (!button.IsEnabled) continue;
                if (button.Content as String != SelectMark) allSelected = false;
            }

            for (int i = 0; i < generations.Length; i++)
            {
                var button = gridButtons[i, sessionIndex];
                if (!button.IsEnabled) continue;
                button.Content = allSelected ? null : SelectMark;
            }

            updateButtons();
        }

        private void selectGeneration(int genIndex)
        {
            bool allSelected = true;
            for (int i = 0; i < sessions.Length; i++)
            {
                var button = gridButtons[genIndex, i];
                if (!button.IsEnabled) continue;
                if (button.Content as String != SelectMark) allSelected = false;
            }

            for (int i = 0; i < sessions.Length; i++)
            {
                var button = gridButtons[genIndex, i];
                if (!button.IsEnabled) continue;
                button.Content = allSelected ? null : SelectMark;
            }

            updateButtons();
        }

        private void selectGrid(int genIndex, int sessionIndex)
        {
            var button = gridButtons[genIndex, sessionIndex];
            if (button.Content as String == SelectMark) button.Content = null;
            else button.Content = SelectMark;

            updateButtons();
        }

        private void updateButtons()
        {
            int count = 0;
            foreach (var button in gridButtons)
            {
                if (button.IsEnabled && button.Content as String == SelectMark) count++;
            }
            buttonOpenDir.IsEnabled = count == 1;
            buttonDelete.IsEnabled = count > 0;
        }

        private SessionIdentifier[] sessions = [];
        private String[] generations = [];
        private Button[,] gridButtons = new Button[0, 0];
        private GenerationProcessStatus?[,] gridStatus = new GenerationProcessStatus?[0, 0];

        private const String SelectMark = "X";
        private LanguageSwitch language;

        private bool closed = false;
    }
}